#include <stdio.h>
#include <sys/poll.h>
#define NETMAP_WITH_LIBS
#include <net/netmap_user.h>
#include <errno.h>
#include <arpa/inet.h>

#pragma pack(1)


#define PROTO_IP 		0x0800
#define PROTO_UDP		17
#define ETH_LEN			6

// 以太网数据帧首部
// 目的地址
// 源地址
// 协议类型 0x0800表示网络层使用的是IP协议
// 总长度 14字节
struct ethhdr {
	unsigned char h_dest[ETH_LEN];
	unsigned char h_src[ETH_LEN];
	unsigned short h_proto;    
};

// proto : TCP 6, UDP 17, ICMP 1
// 总长度 20字节
struct iphdr {
	unsigned char version:4, hdrlen:4;
	unsigned char tos;
	unsigned short length;

	unsigned short id;
	unsigned short flag:3, offset:13;

	unsigned char ttl;
	unsigned char proto;
	unsigned short check;

	unsigned int sip;

	unsigned int dip;
};

// 总长度 8字节
struct udphdr {
	unsigned short sport;
	unsigned short dport;

	unsigned short length;
	unsigned short check;
};


struct udppkt {
	struct ethhdr eh;
	struct iphdr ip;
	struct udphdr udp;

	unsigned char body[0]; // sizeof(body)=0;
};

int main() {
	// eth0  --> ens33
	struct nm_desc *nmr = nm_open("netmap:eth0", NULL, 0, NULL);
	if (nmr == NULL) 
	{
		printf("open netmap:eth0 failed\n");
		return -1;
	}

	struct pollfd pfd = {0};
	pfd.fd = nmr->fd;
	pfd.events = POLLIN;

	while (1) {
		int ret = poll(&pfd, 1, -1);
		if (ret < 0)
		{
			printf("poll error, errno : %d \n", ret);
			continue;
		} 
		if (pfd.revents & POLLIN) {
			struct nm_pkthdr h;
			unsigned char *stream = nm_nextpkt(nmr, &h);
			struct ethhdr *eh = (struct ethhdr*)stream;
			if (ntohs(eh->h_proto) == PROTO_IP) {
				struct udppkt *udp = (struct udppkt *)stream;
				if (udp->ip.proto == PROTO_UDP) {
					int udp_length = ntohs(udp->udp.length);
					udp->body[udp_length-8] = '\0';
					printf("udp --> %s\n", udp->body);
				}
				else
				{
					printf("current protocol not UDP, type %x \n", udp->ip.proto);
				}
			}
			else
			{
				printf("current protocol not IP, type %x \n", ntohs(eh->h_proto));
			}

		}

	}

	return 0;
}

